/**
 * ESP8266类
 *  1. 初始化ESP8266模块
 *  2. 对外提供MqttPublish功能
 */
var log = require("./nlog.js");
var conf = require("./settings.js")
var AT = require("./at.js");
var events = require("events");

function ESP8266() {
    var rtn = {};
    var atDev = AT();
    rtn.event = new events();       // 通过事件将ESP8266接到的数据返回给调用ESP8266的文件
    var intervalTime = 100;         // 开启发数据的间隔时间，0.01s
    var writeEnable = true;         // 是否可写
    var atCmdQueue = [];
    var writeType = 0;              // 写类型，0：单条，1：多条
    var cmdName = "";               // 命令名字
    var setInfo;                    // 配置信息
    var afterConfig = false;        // 是否被ipad配置过
    
    /**
     * 获取App命令函数
     *  说明：从App发来的字符串中提取命令
     *  参数：atMsg，字符串，App发来的字符串
     */
    function GetAppCmd(atMsg) {
        var idx = atMsg.search(':');
        atMsg = atMsg.slice(idx + 1,);
        return JSON.parse(atMsg);
    }

    function DealOK() {
        atDev.event.on("OK", function () {
            log.e("DealOK OK!");
            writeEnable = true;
            if (cmdName == "AT+CWJAP") {
                log.e("AT+CWJAP success!!!");
                rtn.event.emit("WIFI_CONNECTED");
            } else if (cmdName == "AT+MQTTCONN" && afterConfig == true) {
                rtn.event.emit("MQTT_CONNECTED");
            } else if (cmdName == "AT+MQTTSUB") {
                rtn.event.emit("ESP8266_INIT_FINISH")
            }
            if (atCmdQueue.length > 0 && writeType == 1) {
                atCmdQueue.splice(0, 1);
            }
            cmdName = "";
        });
    }

    /**
     * 处理AT发来的ERROR信号
     */
    function DealERROR() {
        atDev.event.on("ERROR", function () {
            log.e("DealERROR ERROR!")
            writeEnable = true;
            cmdName = "";
            atCmdQueue.splice(0, 1);
        });
    }

    /**
     * 处理AT发来的Busy p信号
     */
    function DealBUSY_P() {
        atDev.event.on("BUSY_P", function () {
            log.e("DealBUSY_P busy p!")
        });
    }

    /**
     * 发Tcp函数
     *  说明：将字符串通过tcp发送出去
     *  参数：tcpStr，字符串，要发送的内容
     */
    function SendTcp(tcpStr) {
        log.e("SendTcp start!!!");
        var len = tcpStr.length;
        var ATlen = 'AT+CIPSEND=0,' + len + '\r\n';
        var atCmds = [
            ATlen,
            tcpStr
        ];
        PushAtCmds(atCmds);
        WriteCmds();
    }

    /**
     * App获参函数
     *  说明：智慧萌点App登录成功后，网关将配置信息发送给App
     */
    function AppGetParm() {
        log.e("AppGetParm start!!!")
        setInfo = conf.GetParam();
        var paraStr = '{"DeviceID":"'+setInfo.DeviceID+'","SSID":"'+setInfo.WIFI.ssid+'","PWD":"'+setInfo.WIFI.passWord+'","ServerIP":"'+setInfo.MQTT.brokerIp+'","PORT":"1883","ADDR":"'+setInfo.MQTT.ADDR+'"}';
        log.e(paraStr);
        SendTcp(paraStr);
    }

    /**
     * App配参函数
     *  说明：智慧门店App点击配置后，发出配置参数，写入到配置文件，写入成功后再试图连一次WIFI
     *  参数：parmDict，字典类型，要存入配置文件的数据
     */
    function AppSetParm(parmDict) {
        log.e(parmDict);
        conf.SaveParam(parmDict);
        var paraStr = '{"DeviceID":"' + parmDict["DeviceID"] + '","Status":"Received"}';
        SendTcp(paraStr);
        TryConnectWifi();
    }

    /**
     * 处理其它信息配置参数函数
     *  说明：
     *      1.接收到IPAD的配置信息后，根据字典中元素的个数，调用不同的函数
     *      2.处理其他信息
     */
     function DealWithOthers() {
        atDev.event.on("UART_RECV", function(uartMsg) {
            log.e(uartMsg);
            if (uartMsg.indexOf("+IPD") != -1) {
                log.e(uartMsg);
                var appMsgDic = GetAppCmd(uartMsg);
                var msgLen = Object.keys(appMsgDic).length
                if (msgLen == 1) {
                    AppGetParm();
                } else if (msgLen == 7) {
                    afterConfig = true;
                    AppSetParm(appMsgDic);
                }
            } else if (uartMsg.indexOf("AT") == -1){
                var mqttMsg = uartMsg.split(',')[uartMsg.split(',').length - 1].trim();
                rtn.event.emit("MQTT_MSG", mqttMsg);
            }
        });
    }

    /**
     * 处理路由函数
     *  说明：开启OK，ERROR，BUSY_P，IPD事件接收
     */
    function DealRoute() {
        DealOK();
        DealERROR();
        DealBUSY_P();
        DealWithOthers();
    }

    /**
     * 获取命令名字函数
     *  说明：每次发命令前，从AT命令中获取当前命令的名字，方便返回OK或ERROR时处理
     *  参数：atCmd，AT命令字符串
     */
    function GetCmdName(atCmd) {
        var cmdName = "";
        if (atCmd.indexOf("=")) {
            cmdName = atCmd.split("=")[0];
        } else {
            cmdName = atCmd.split("\r")[0];
        }
        return cmdName;
    }

    /**
     * 写单条命令函数
     *  说明：写单条命令
     *  参数：cmdStr，AT命令字符串
     */
    function WriteCmd(cmdStr) {
        var cmdTimer = setInterval(function() {
            if (writeEnable && atCmdQueue.length == 0) {
                cmdName = GetCmdName(cmdStr);
                writeEnable = false;
                writeType = 0;
                atDev.WriteATCmd(cmdStr);
                clearInterval(cmdTimer)
            }
        }, intervalTime);
    }

    /**
     * 写多条命令函数
     *  说明：在PushAtCmds后面调用，将当前atCmdQueue中的命令全部发出
     */
    function WriteCmds() {
        var cmdsTimer = setInterval(function() {
            if (writeEnable && atCmdQueue.length != 0) {
                writeEnable = false;
                writeType = 1;
                cmdName = GetCmdName(atCmdQueue[0]);
                atDev.WriteATCmd(atCmdQueue[0]);
            }
            if (atCmdQueue.length == 0) {
                clearInterval(cmdsTimer);
            }
        }, intervalTime);
    }

    /**
     * esp8266重启函数
     *  说明：重启ESP8266
     */
    function Restart() {
        WriteCmd("AT+RESTORE\r\n");
    }

    /**
     * AT命令入队函数
     *  说明：写多条AT命令时，需要先将这些命令填入atCmdQueue中
     *  参数：atcmds，字符串数组，存储多条AT命令
     */
    function PushAtCmds(atCmds) {
        var pushTimers = setInterval(function(){
            if (atCmdQueue.length == 0) {
                clearInterval(pushTimers);
                for (var i = 0; i < atCmds.length; i++) {
                    atCmdQueue.push(atCmds[i]);
                }
            }
        }, intervalTime);
    }

    /**
     * 开启AP+STA函数
     *  说明：根据配置信息开启AP+STA模式
     */
    function StartAP_STA() {
        var CWSAP = 'AT+CWSAP="'+setInfo.AP.ssid+'","'+setInfo.AP.passWord+'",11,3\r\n';  // 开启WIFI热点命令
        var atCmds = [
            "AT+CWMODE=3\r\n",      // 设置AP+STA模式
            CWSAP,    // 开启WIFI热点
            "AT+CIPMUX=1\r\n",      // 开启多连接
            "AT+CIPSERVER=1,9999\r\n",  // 开启服务端
            "AT+CIFSR\r\n"      // 查看MAC地址和IP
        ];
        PushAtCmds(atCmds);
        WriteCmds();
    }

    /**
     * 连接WIFI函数
     *  说明：读取配置文件中的WIFI信息，连接WIFI
     */
    function TryConnectWifi() {
        log.e("TryConnectWifi start!!!");
        setInfo = conf.GetParam();
        var CWJAP = 'AT+CWJAP="'+setInfo.WIFI.ssid+'","'+setInfo.WIFI.passWord+'"\r\n';
        WriteCmd(CWJAP);
    }

    /**
     * 初始化MQTT函数
     *  1. 清除MQTT连接信息(断连MQTT)
     *  2. 配置MQTT连接信息
     *  3. 连接MQTT服务器
     *  4. 订阅MQTT主题
     */
    function MqttInit() {
        rtn.event.on("WIFI_CONNECTED", function() {
            var MQTTCLEAN = 'AT+MQTTCLEAN=0\r\n';
            var MQTTUSERCFG = 'AT+MQTTUSERCFG=0,1,"'+setInfo.MQTT.clientID+'","'+setInfo.MQTT.userName+'","'+setInfo.MQTT.passWord+'",0,0,""\r\n';    // 设置MQTT用户配置
            var MQTTCONN = 'AT+MQTTCONN=0,"'+setInfo.MQTT.brokerIp+'",1883,0\r\n';     // 连接MQTT服务器
            var MQTTSUB = 'AT+MQTTSUB=0,"'+setInfo.MQTT.subTopic+'",0\r\n';            // 订阅MQTT主题
            var atCmds = [
                MQTTCLEAN,
                MQTTUSERCFG,    // 设置MQTT用户配置
                MQTTCONN,       // 连接MQTT服务器
                MQTTSUB,        // 订阅MQTT主题
            ];
            PushAtCmds(atCmds);
            WriteCmds();
        });
        rtn.event.on("MQTT_CONNECTED", function() {
            var paraStr = '{"DeviceID":"' + setInfo.DeviceID + '","Status":"success"}';
            SendTcp(paraStr);
            afterConfig = false;
        });
    }

    /**
     * MQTT发布函数
     *  说明：接收app.js的调用，发布MQTT消息
     *  参数：payLoad，字符串变量，发布的消息
     */
    rtn.MqttPublish = function(payLoad) {
        var MQTTPUB = 'AT+MQTTPUB=0,"'+setInfo.MQTT.pubTopic+'","'+payLoad+'",1,0\r\n';  // 发布MQTT字符串消息
        WriteCmd(MQTTPUB);
    }

    /**
     * 初始化ESP8266
     *  1. 获取配置参数
     *  2. 设置接收处理路由
     *  3. 重启ESP8266
     *  4. 设置AP+STA模式
     *  5. 尝试连接WIFI
     *  6. 连接MQTT
     */
    function InitESP8266() {
        setInfo = conf.GetParam();
        DealRoute();
        Restart();
        var timeOut = setTimeout(function() {
            clearTimeout(timeOut);
            StartAP_STA();
            TryConnectWifi();
            MqttInit();
        }, 2000);
    }

    InitESP8266();

    return rtn;
}

module.exports = ESP8266;